﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;
using JmShared;
using Windows.Networking.Sockets;
using JiveMessenger.Views;
using JiveMessenger.ViewModels;
using System.Diagnostics;
using System.Threading.Tasks;
using JiveMessenger.Utilities;
using JiveMessenger.User;
using System.Collections.ObjectModel;
using JiveMessenger.Models;
using Windows.UI;
using Windows.UI.Text;
using JiveMessenger.Common;
using JiveMessenger.Log;
using Newtonsoft.Json;
using Windows.UI.ViewManagement;
using Windows.UI.Notifications;
using GalaSoft.MvvmLight.Messaging;
using Windows.UI.Popups;
using GalaSoft.MvvmLight.Threading;
// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227

namespace JiveMessenger
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    public sealed partial class App : Application
    {
#if WINDOWS_PHONE_APP
        private TransitionCollection transitions;
        private ContinuationManager continuationManager;

#endif

        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {

            Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = Windows.Globalization.Language.CurrentInputMethodLanguageTag;
            SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<ViewModelTab>));
            SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<ViewModelChat>));
            SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<ViewModelGroupChat>));
            SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<ViewModelPrivateMessage>));
            SuspensionManager.KnownTypes.Add(typeof(ViewModelTab));
            SuspensionManager.KnownTypes.Add(typeof(ViewModelChat));
            SuspensionManager.KnownTypes.Add(typeof(ViewModelGroupChat));
            SuspensionManager.KnownTypes.Add(typeof(ViewModelPrivateMessage));
            SuspensionManager.KnownTypes.Add(typeof(RangeObservableCollection<MessageModel>));
            SuspensionManager.KnownTypes.Add(typeof(MessageModel));
            SuspensionManager.KnownTypes.Add(typeof(Color));
            SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<IContact>));
            SuspensionManager.KnownTypes.Add(typeof(IContact));
            SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<JiveContactModel>));
            SuspensionManager.KnownTypes.Add(typeof(JiveContactModel));
            SuspensionManager.KnownTypes.Add(typeof(FontStyle));
            SuspensionManager.KnownTypes.Add(typeof(FontWeight));
            SuspensionManager.KnownTypes.Add(typeof(JiveCustomEmoticonModel));
            SuspensionManager.KnownTypes.Add(typeof(JiveDefaultEmoticonModel));
            TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueueForWide310x150(true);
            this.InitializeComponent();
            this.Suspending += this.OnSuspending;
            this.Resuming += this.OnResuming;
            this.UnhandledException += Application_UnhandledException;

            if (AppSettings.Instance.RequestedThemeSetting == "Dark")
                this.RequestedTheme = ApplicationTheme.Dark;
            else if (AppSettings.Instance.RequestedThemeSetting == "Light")
                this.RequestedTheme = ApplicationTheme.Light;

        }
        private void RegisterNavService()
        {
            ViewModelLocator locator = (ViewModelLocator)Application.Current.Resources["Locator"];
            locator.NavService.Configure("CropImagePage", typeof(CropImagePage));

#if WINDOWS_PHONE_APP
            locator.NavService.Configure("LoginPage", typeof(LoginPage));
            locator.NavService.Configure("MainPage", typeof(MainPage));
            locator.NavService.Configure("SettingsPage", typeof(SettingsPage));
            locator.NavService.Configure("MessageDownloadPage", typeof(MessageDownloadPage));
            locator.NavService.Configure("AddContactPage", typeof(AddContactPage));
            locator.NavService.Configure("GroupAndContactNavigationPage", typeof(GroupAndContactNavigationPage));
            locator.NavService.Configure("NotificationsPage", typeof(NotificationsPage));
            locator.NavService.Configure("RenameGroupPage", typeof(RenameGroupPage));
            locator.NavService.Configure("InviteToGroupPage", typeof(InviteToGroupPage));
            locator.NavService.Configure("ManageGroupPage", typeof(ManageGroupPage));
            locator.NavService.Configure("GetUserEmoticonsPage", typeof(GetUserEmoticonsPage));
            locator.NavService.Configure("AddEmoticonPage", typeof(AddEmoticonPage));
#endif
        }
        private void InitMessengers()
        {
#if WINDOWS_PHONE_APP
            Messenger.Default.Register<JiveToastMessage>(this, msg =>
            {
                DispatcherHelper.CheckBeginInvokeOnUI(() =>
                {
                    PromptHelper.ShowToastPrompt(msg.Title, msg.Message, msg.DisplayTime > 0 ? msg.DisplayTime : 3000, msg.WrapMode);
                });
            });
            Messenger.Default.Register<JiveDialogMessage>(this, msg =>
            {
                DispatcherHelper.CheckBeginInvokeOnUI(() =>
                {
                    PromptHelper.ShowMessagePrompt(msg.Title, msg.Message);
                });
            });
#endif
            Messenger.Default.Register<NotificationMessageAction<bool>>(this, async msg =>
            {
                switch (msg.Notification)
                {
                    case "QueryDialog":
                        {
                            bool result = false;
                            JiveDialogQuery query = msg.Target as JiveDialogQuery;
                            MessageDialog dialog = new MessageDialog(query.Title, query.Message);
                            dialog.Commands.Add(new UICommand("Yes", (command) =>
                            {
                                result = true;
                            }));
                            dialog.Commands.Add(new UICommand("No"));
                            await dialog.ShowAsync();

                            msg.Execute(result);
                            break;
                        }
                }

            });

        }
        private static void SetLockscreenState(bool isDisabled)
        {
            Windows.System.Display.DisplayRequest KeepScreenOnRequest = new Windows.System.Display.DisplayRequest();
            try
            {
                if (isDisabled)
                    KeepScreenOnRequest.RequestActive();
                else
                    KeepScreenOnRequest.RequestRelease();
            }
            catch { }
        }

        static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            e.SetObserved();
            ExceptionHandler.LogException(e.Exception);
        }
        private void Application_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Debug.WriteLine(e.Exception.ToString());
            ExceptionHandler.LogException(e.Exception);
            e.Handled = true;
        }

#if WINDOWS_PHONE_APP
        /// <summary>
        /// Handle OnActivated event to deal with File Open/Save continuation activation kinds
        /// </summary>
        /// <param name="e">Application activated event arguments, it can be casted to proper sub-type based on ActivationKind</param>
        protected async override void OnActivated(IActivatedEventArgs e)
        {
            base.OnActivated(e);
            continuationManager = new ContinuationManager();

            var continuationEventArgs = e as IContinuationActivatedEventArgs;

            Frame rootFrame = CreateRootFrame();
            await RestoreStatusAsync(e.PreviousExecutionState);

            if (rootFrame.Content == null)
            {
                rootFrame.Navigate(typeof(MainPage));
            }


            if (continuationEventArgs != null)
            {
                //Frame scenarioFrame = MainPage.Current.FindName("ScenarioFrame") as Frame;
                //if (scenarioFrame != null)
                //{
                //    // Call ContinuationManager to handle continuation activation
                continuationManager.Continue(continuationEventArgs);//, rootFrame);
                //}
            }

            Window.Current.Activate();
        }
#endif
        private Frame CreateRootFrame()
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new ThemeAwareFrame();

                // Set the default language
                rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
                rootFrame.NavigationFailed += OnNavigationFailed;
                SuspensionManager.RegisterFrame(rootFrame, "MainFrame");
                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            return rootFrame;
        }
        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }
        private async Task RestoreStatusAsync(ApplicationExecutionState previousExecutionState)
        {
            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (previousExecutionState == ApplicationExecutionState.Terminated)
            {
                // Restore the saved session state only when appropriate
                try
                {

                    await SuspensionManager.RestoreAsync();
                }
                catch (SuspensionManagerException)
                {
                    //Something went wrong restoring state.
                    //Assume there is no state and continue
                }
            }
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="e">Details about the launch request and process.</param>
        protected override async void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif
            var locator = VmHelper.Locator = (ViewModelLocator)Application.Current.Resources["Locator"];
            Frame rootFrame = CreateRootFrame();

            await RestoreStatusAsync(e.PreviousExecutionState);

            if (rootFrame.Content == null)
            {
                //Initiate Log channel and Log sessions
                await Logger.GetLogger().InitiateLogger();

                //Delete the logfile which are beyond the dates
                await Logger.GetLogger().Deletefile();
                // set sync context for ui thread so async void exceptions can be handled, keeps process alive
                AsyncSynchronizationContext.Register();

                // ensure unobserved task exceptions (unawaited async methods returning Task or Task<T>) are handled
                TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
                GalaSoft.MvvmLight.Threading.DispatcherHelper.Initialize();
                SetLockscreenState(AppSettings.Instance.IsLockscreenDisabledSetting);
                InitMessengers();
                RegisterNavService();
                AppSettings.Instance.PropertyChanged += AppSettings_PropertyChanged;

#if WINDOWS_PHONE_APP
                // Removes the turnstile navigation for startup.
                if (rootFrame.ContentTransitions != null)
                {
                    this.transitions = new TransitionCollection();
                    foreach (var c in rootFrame.ContentTransitions)
                    {
                        this.transitions.Add(c);
                    }
                }

                rootFrame.ContentTransitions = null;
                rootFrame.Navigated += this.RootFrame_FirstNavigated;
#endif


                if (string.IsNullOrEmpty(AppSettings.Instance.UsernameSetting) || string.IsNullOrEmpty(CredentialsManager.GetStoredPasswordForUser(AppSettings.Instance.UsernameSetting)))
                {
                    if (!rootFrame.Navigate(typeof(LoginPage), e.Arguments))
                    {
                        throw new Exception("Failed to create login page");
                    }
                }
                else
                {
                    // When the navigation stack isn't restored navigate to the first page,
                    // configuring the new page by passing required information as a navigation
                    // parameter
                    if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
                    {
                        throw new Exception("Failed to create initial page");
                    }
                }
            }
            Task.Factory.StartNew(async () =>
            {
                var foo = AppSettings.Instance.ServerListSetting;
            });
            // Ensure the current window is active
            Window.Current.Activate();



            if (e.Arguments is string && !string.IsNullOrEmpty((string)e.Arguments))
            {
                string decodedUrl = System.Net.WebUtility.HtmlDecode((string)e.Arguments);

                ChatMessage msg = JsonConvert.DeserializeObject<ChatMessage>(decodedUrl);
                ViewModelChat vm = locator.CurrentClient.GetOrOpenChatViewModel(msg);
                locator.ViewModelMainPage.CurrentActiveViewModel = vm;
                locator.ViewModelMainPage.SelectedPivotItemIndex = 0;
                //if (msg.MessageType == MessageType.PrivateMessage)
                //    locator.CurrentClient.DisplayPrivateMessage(msg);
                //else if (msg.MessageType == MessageType.GroupMessage)
                //    locator.CurrentClient.DisplayGroupMessage(msg);
            }

            //try
            //{
            //    // Read the contents of the Certificate file
            //    System.Uri certificateFile = new System.Uri("ms-appx:///Assets/JiveMessengerServer.cer");
            //    Windows.Storage.StorageFile file = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(certificateFile);
            //    Windows.Storage.Streams.IBuffer certBlob = await Windows.Storage.FileIO.ReadBufferAsync(file);
            //    // Create an instance of the Certificate class using the retrieved certificate blob contents
            //    Windows.Security.Cryptography.Certificates.Certificate rootCert = new Windows.Security.Cryptography.Certificates.Certificate(certBlob);
            //    // Get access to the TrustedRootCertificationAuthorities for your own app (not the system one)
            //    Windows.Security.Cryptography.Certificates.CertificateStore trustedStore = Windows.Security.Cryptography.Certificates.CertificateStores.TrustedRootCertificationAuthorities;
            //    // Add the certificate to the TrustedRootCertificationAuthorities store for your app
            //    trustedStore.Add(rootCert);
            //}
            //catch (Exception oEx)
            //{
            //    // Catch and report exceptions
            //    System.Diagnostics.Debug.WriteLine("Exception Adding cert: " + oEx.Message);
            //}
        }

        async void AppSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "IsLockscreenDisabledSetting":
                    SetLockscreenState(AppSettings.Instance.IsLockscreenDisabledSetting);
                    break;
                case "RequestedThemeSetting":
                    //PromptHelper.ShowMessagePrompt("Change Theme", "The app must be restarted for the new theme to take effect");
                    await Task.Delay(50);
                    SetRequestedTheme();
                    break;
            }


        }

#if WINDOWS_PHONE_APP
        /// <summary>
        /// Restores the content transitions after the app has launched.
        /// </summary>
        /// <param name="sender">The object where the handler is attached.</param>
        /// <param name="e">Details about the navigation event.</param>
        private void RootFrame_FirstNavigated(object sender, NavigationEventArgs e)
        {
            var rootFrame = sender as Frame;
            rootFrame.ContentTransitions = this.transitions ?? new TransitionCollection() { new NavigationThemeTransition() };
            //   rootFrame.ContentTransitions = this.transitions ?? new TransitionCollection() { new NavigationThemeTransition() { DefaultNavigationTransitionInfo = new ContinuumNavigationTransitionInfo() } };
            rootFrame.Navigated -= this.RootFrame_FirstNavigated;
        }
#endif

        private void SetRequestedTheme()
        {
            if (AppSettings.Instance.RequestedThemeSetting == "Dark")
                (Window.Current.Content as ThemeAwareFrame).AppTheme = ElementTheme.Dark;
            else if (AppSettings.Instance.RequestedThemeSetting == "Light")
                (Window.Current.Content as ThemeAwareFrame).AppTheme = ElementTheme.Light;
        }



        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            await SuspensionManager.SaveAsync();
            //ViewModelLocator locator = Application.Current.Resources["Locator"] as ViewModelLocator;
            //IClient currentClient = locator.CurrentClient;
            //if (currentClient.IsLoggedIn)
            //{
            //    try
            //    {
            //        DeviceStatus status = new DeviceStatus(currentClient.CurrentUserInfo.UserID, false);
            //        await currentClient.Connection.SendCommand(status, ClientCommands.DeviceStatusUpdate);

            //    }
            //    catch { }
            // }
            // TODO: Save application state and stop any background activity
            deferral.Complete();
        }

        private void OnResuming(object sender, object e)
        {

        }
    }
}